package net.borlis.log;

import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author alex@borlis.net
 */
@Interceptor
@SimpleLogger
public class SimpleLoggerInterceptor {

    private static final int MILLISECONDS = 1000;
    private static final String NULL = "null";

    @Inject
    private Logger logger;

    @AroundInvoke  //todo:: improve it!!! add the log level to the annotation!!!
    public Object logRunningCode(InvocationContext ctx) throws Exception {//NOPMD
        // there is a conflict between SONAR/CDI
        final SimpleLogger annotation = ctx.getMethod().getAnnotation(SimpleLogger.class);
        final boolean statistic = annotation.statistic();
        final boolean input = annotation.input();
        final boolean output = annotation.output();
        // -=-=-=-
        logger.log(Level.INFO, annotation.logMessage());
        // -=-=-=-
        logger.log(Level.FINE, "The class name: " + ctx.getMethod().getDeclaringClass().getName());
        logger.log(Level.FINE, "The method name: " + ctx.getMethod().getName());
        logger.log(Level.FINE, "The content data: " + ctx.getContextData().toString());
        // -=-=-=-=-=-
        logger.log(Level.INFO, " -> method {" + ctx.getMethod().getDeclaringClass().getName() +
                "}" + ctx.getMethod().getName() + " started...");
        if (input) {
            Object[] parameters = ctx.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                final boolean isNull = parameters[i]!=null;
                String simpleName = isNull?parameters[i].getClass().getSimpleName():NULL;
                String simpleValue = parameters[i]!=null?String.valueOf(parameters[i]):NULL;
//            for (Object parameter : ctx.getParameters()) {
                logger.log(Level.INFO, " -> method parameter: " + i + ":type[" + simpleName + "]=" + simpleValue);
            }
        }
        try {
            long start = System.currentTimeMillis();
            Object result = ctx.proceed();
            long finish = System.currentTimeMillis();
            logger.log(Level.INFO, " <- method {" + ctx.getMethod().getDeclaringClass().getName() +
                    "}" + ctx.getMethod().getName() + " finished...");
            if (statistic) {
                logger.log(Level.INFO, " <- method statistic: time= " + (finish-start)/MILLISECONDS + " sec.");
            }
            if (output) {
                String resultType = (result==null?null:result.getClass().getSimpleName());
                logger.log(Level.INFO, " <- method result: type[" + resultType + "]=" + result);
            }
            return result;
            // -=-=-=-=-=-
        } catch (Exception e) {
            logger.log(Level.SEVERE, " <+ method {" + ctx.getMethod().getDeclaringClass().getName() +
                    "}" + ctx.getMethod().getName() + " crashed...");
            logger.log(Level.SEVERE, " <+ method exception: type[" + e.getClass().getSimpleName() + "]=" + e.getMessage());
            throw e;
        }
    }

}
